package cn.s1995.sloth.bizs.service.common.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.s1995.sloth.admin.api.dto.FileUploadConfigDTO;
import cn.s1995.sloth.admin.api.entity.SysPublicParam;
import cn.s1995.sloth.bizs.constant.RedisKeyCst;
import cn.s1995.sloth.bizs.constant.SysPublicParamKeyCst;
import cn.s1995.sloth.bizs.constant.TimeCst;
import cn.s1995.sloth.bizs.service.common.CacheService;
import cn.s1995.sloth.bizs.util.RedisUtil;
import cn.s1995.sloth.common.data.resolver.ParamResolver;
import cn.s1995.sloth.common.security.service.SlothUser;
import jakarta.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * CacheServiceImpl
 *
 * @Author penf
 * @Description 缓存接口实现
 * @Date 2022/10/26 23:15
 */
@Service
public class CacheServiceImpl implements CacheService {

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Map<String, SysPublicParam> getSysParams(String... keys) {
        Map<String, Object> res = ParamResolver.getMap(keys);
        if (CollUtil.isNotEmpty(res)) {
            Map<String, SysPublicParam> collect = res.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> {
                SysPublicParam sysPublicParam = new SysPublicParam();
                sysPublicParam.setPublicKey(e.getKey());
                sysPublicParam.setPublicValue(String.valueOf(e.getValue()));
                return sysPublicParam;
            }));
            return collect;
        } else {
            return new HashMap<>();
        }
    }

    @Override
    public void removeUserInfo(String token) {
        redisUtil.del(RedisKeyCst.TOKEN + token);
    }

    @Override
    public boolean isEnableSMS() {
        return ParamResolver.getBool(SysPublicParamKeyCst.IS_ENABLE_SMS, Boolean.FALSE);
    }

    @Override
    public boolean setVerifyCode(Integer scene, String val, String verificationCode) {
        return redisUtil.set(getVerifyCodeKey(RedisKeyCst.VERIFY_CODE, scene, val), verificationCode, TimeCst.TIME_60SECOND);
    }

    @Override
    public String getVerifyCode(Integer scene, String val) {
        return redisUtil.getString(getVerifyCodeKey(RedisKeyCst.VERIFY_CODE, scene, val));
    }

    @Override
    public void removeVerifyCode(Integer scene, String mobile) {
        redisUtil.del(getVerifyCodeKey(RedisKeyCst.VERIFY_CODE, scene, mobile));
    }

    @Override
    public Long getSmsExpire(Integer scene, String mobile) {
        return redisUtil.getExpire(getVerifyCodeKey(RedisKeyCst.VERIFY_CODE, scene, mobile));
    }

    @Override
    public Long setSmsSendNum(Integer scene, String mobile) {
        return redisUtil.incr4Expired(
                getVerifyCodeKey(RedisKeyCst.SMS_SEND_NUM, scene, mobile),
                1L,
                TimeCst.TIME_30MINUTE
        );
    }

    @Override
    public void removeSmsSendNum(Integer scene, String mobile) {
        redisUtil.del(getVerifyCodeKey(RedisKeyCst.SMS_SEND_NUM, scene, mobile));
    }

    @Override
    public Long getSmsSendNum(Integer scene, String mobile) {
        return redisUtil.getLong(getVerifyCodeKey(RedisKeyCst.SMS_SEND_NUM, scene, mobile));
    }

    @Override
    public void setDisabledSms(int scene, String mobile) {
        redisUtil.set(
                getVerifyCodeKey(RedisKeyCst.SMS_DISABLED, scene, mobile),
                String.format("%s:%s", scene, mobile),
                TimeCst.TIME_ONE_HOUR
        );
    }

    @Override
    public String getDisabledSms(int scene, String mobile) {
        return redisUtil.getString(getVerifyCodeKey(RedisKeyCst.SMS_DISABLED, scene, mobile));
    }

    @Override
    public long getSmsSendNumLimit() {
        return ParamResolver.getLong(SysPublicParamKeyCst.SMS_SEND_NUM_LIMIT, 5L);
    }

    @Override
    public long getOrderAutoCancelTime() {
        return ParamResolver.getLong(SysPublicParamKeyCst.ORDER_AUTO_CANCEL_TIME, 15L);
    }

    @Override
    public long getOrderAutoConfirmTime() {
        return ParamResolver.getLong(SysPublicParamKeyCst.ORDER_AUTO_CONFIRM_TIME, 15L);
    }

    @Override
    public long getShoppingAddressMaxLimit() {
        return ParamResolver.getLong(SysPublicParamKeyCst.SHOPPING_ADDRESS_MAX_LIMIT, 10L);
    }

    @Override
    public FileUploadConfigDTO getFileUploadConfig() {
        String json = ParamResolver.getStr(
                SysPublicParamKeyCst.FILE_UPLOAD_CONFIG,
                "{\"image\":{\"limit\":0.2,\"spec\":\"375*750\",\"quality\":0.8},\"video\":{\"limit\":30,\"isScreenshot\":true,\"screenshotTime\":3}}"
        );
        return JSONUtil.toBean(json, FileUploadConfigDTO.class);
    }

    /**
     * 获取场景缓存key
     *
     * @param key
     * @param scene
     * @param val
     * @return
     */
    private String getVerifyCodeKey(String key, Integer scene, String val) {
        return String.format("%s%s:%s", key, scene, val);
    }

	@Override
	public Long getUidByToken(String token) {
		if(StrUtil.isNotBlank(token)) {
			token = token.split(" ")[1];
			try {
				Object cache = redisTemplate.opsForValue().get("1::token::access_token::" + token);
				if(ObjectUtil.isNotNull(cache)) {
					OAuth2Authorization oAuth2Authorization = (OAuth2Authorization) cache;
					UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = oAuth2Authorization.getAttribute("java.security.Principal");
					SlothUser user = (SlothUser) usernamePasswordAuthenticationToken.getPrincipal();
					return user.getId();
				}
			} catch (Exception e) {
				return null;
			}
		}
		return null;

	}

}
